

#include "loop_event.hpp"
#include "channel.h"
#include "define.h"
#include "epoll_event.hpp"
#include <cerrno>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <mutex>
#include <iostream>
#include <sys/epoll.h>
#include <vector>
#include "timer_task.h"


LoopEvent::LoopEvent()
{
    m_epoll_fd = epoll_create(1024);
    m_channel_id_count = 0;
    m_loop_status      = true;
}

LoopEvent::~LoopEvent()
{
    if (m_channel_map.empty())
    {
        // delete memory
        m_channel_map.clear();
    }
}

void LoopEvent::Run()
{
    std::vector<struct epoll_event> event_vec;
    event_vec.resize(1500);

    m_task_timer = std::shared_ptr<TaskTimer>( new TaskTimer(this));
    m_task_timer->StartTaskTimer();

    while(m_loop_status)
    {
        int event_count = epoll_wait(m_epoll_fd,&(*event_vec.begin()), 1500, 1);
        for (int index = 0; index < event_count; index++)
        {
            auto & event = event_vec[index];
            auto iter = m_channel_map.find(event.data.u64);
            if (iter != m_channel_map.end())
            {
                iter->second->EventCallback(event.events);
            }
        }
        m_task_timer->DoTimer();
        DoTask();
    }
}

void LoopEvent::PushTask(TaskCallback &&task)
{
    std::unique_lock<std::mutex> lk(m_mtx);
    m_task_vec.push_back(task);
}

void LoopEvent::PushAfterTask(int64_t after_tm_ms, TaskCallback &&func)
{
    if (m_task_timer)
    {
        m_task_timer->PushTask(after_tm_ms, std::forward<TaskCallback>(func));
    }
}

void LoopEvent::DoTask()
{
    std::vector<TaskCallback> callback_vector;
    {
        // add muter
        std::unique_lock<std::mutex> lk(m_mtx);
        callback_vector.swap(m_task_vec);
    }
    for (auto & data : callback_vector)
    {
        data();
    }
}

int64_t LoopEvent::AddEventType(std::shared_ptr<Channel> channel, int event_type)
{
    int64_t index = m_channel_id_count++;
    struct epoll_event ep;
    memset(&ep, 0, sizeof(ep));

    ep.events   = event_type;
    ep.data.u64 = index;

    int result = epoll_ctl(m_epoll_fd, EPOLL_CTL_ADD, channel->GetSocketFd(), &ep);
    if (result < 0)
    {
        std::cout << "Error: epoll_ctl add failed : " << result << " and error code : " << errno << " fd : " << channel->GetSocketFd() << std::endl;
    }
    else
    {
        // std::cout << "add channel_id : " << index << "\tsock fd : " << channel->GetSocketFd() << std::endl;
    }
    m_channel_map[index] = channel;
    return index;
}

void LoopEvent::Update(int64_t channel_id, int event_type)
{
    struct epoll_event ep;
    memset(&ep, 0, sizeof(ep));

    auto channel = m_channel_map.find(channel_id);

    ep.events = event_type;
    ep.data.u64 = channel_id;

    int result = epoll_ctl(m_epoll_fd, EPOLL_CTL_MOD, channel->second->GetSocketFd(), &ep);
    if (result < 0)
    {
        std::cout << "Error: epoll_ctl mod failed : " << result << std::endl;
    }
    else
    {
        // std::cout << "update channel_id : " << channel_id << "\tsock fd : " << channel->second->GetSocketFd() << std::endl;
    }
}

void LoopEvent::Remove(int64_t channel_id, int event_type)
{
    struct epoll_event ep;
    memset(&ep, 0, sizeof(ep));

    auto channel = m_channel_map.find(channel_id);
    if (channel == m_channel_map.end())
    {
        return;
    }
    ep.events =event_type;
    ep.data.u64 = channel_id;
    int result = epoll_ctl(m_epoll_fd, EPOLL_CTL_DEL, channel->second->GetSocketFd(), &ep);
    if (result < 0)
    {
        std::cout << __func__ << " Error: epoll_ctl mod failed : " << result << "\terrno code : " << errno << std::endl;
    }
    else
    {
        // std::cout << "remove channel_id : " << channel_id << "\tsock fd : " << channel->second->GetSocketFd() << std::endl;    
    }
    m_channel_map.erase(channel);
}

void LoopEvent::StopLoopEvent(bool status)
{
    PushTask([this, status](){

       m_loop_status = status;
    });
}



